/****************************************************************************
 * Copyright (C) 2011
 * by Dj_Skual
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you
 * must not claim that you wrote the original software. If you use
 * this software in a product, an acknowledgment in the product
 * documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and
 * must not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 *
 * miibrowser.cpp
 *
 * for SaveGame Manager GX 2011
 ***************************************************************************/
#include <algorithm>
#include <wctype.h>

#include "../../Memory/MemTools.h"
#include "../../FileOperations/Nand.hpp"
#include "miibrowser.h"

MiiBrowser::MiiBrowser()
	:Browser()
{
	SearchChars.clear();
	
	//!Reset and prepare browser
	ResetBrowser();
	
	GetList();
}

MiiBrowser::~MiiBrowser()
{
	ResetBrowser();
}

void MiiBrowser::ResetBrowser()
{
	for(u32 i = 0; i < browserList.size(); ++i)
		delete browserList.at(i);
	
	browserList.clear();
	FileFilter. clear();
	
	browserSelIndex = -1;
}

void MiiBrowser::AddEntry()
{
	MiiStruct * newMii = new MiiStruct;
	newMii->name = L"";
	newMii->creator = L"";
	newMii->position = 0;
	newMii->female = false;
	newMii->month = 0;
	newMii->day = 0;
	newMii->favColor = 0;
	
	browserList.push_back(newMii);
}

void MiiBrowser::SetSelectedIndex(int ind)
{
	if(browserSelIndex == ind)
		return;
	
	browserSelIndex = ind;
	IndexChanged();
}

void MiiBrowser::RemoveEntry(int ind)
{
	if(ind < 0 || ind >= (int) browserList.size())
		return;
	
	browserList.erase(browserList.begin() + ind);
}

static bool NameSortCallback(const MiiStruct *a, const MiiStruct *b)
{
	return (stricmp((wstr2str(((MiiStruct *)a)->name)).c_str(), (wstr2str(((MiiStruct *)b)->name)).c_str()) < 0);
}

void MiiBrowser::GetList()
{
	ResetBrowser();
	
	s32 fh = Nand::OpenRead(MII_FILE);
	if (fh < 0)
		return;	
	
	//! Get Mii data
	u32 tsize = (MII_SIZE * MII_MAX) + MII_HEADER;
	
	char* miidata = (char*)MemTools::AllocateMemory_32(tsize);
	memset(miidata, 0, round_up(tsize, 32));
	
	if (Nand::Read(fh, (u8*)miidata, tsize) < 0)
	{
		Nand::Close(fh);
		free(miidata);
		miidata = NULL;
		return;
	}
	Nand::Close(fh);
	
	if (miidata[0] != 'R' || miidata[1] != 'N' || miidata[2] != 'O' || miidata[3] != 'D')
	{
		gprintf("Mii version %c%c%c%c is not compatible with libmii\n", miidata[0], miidata[1], miidata[2], miidata[3]);
		free(miidata);
		miidata = NULL;
		return;
	}
	else
	{
		int cnt = 0;
		for (int pos = 0; pos < MII_MAX; pos++)
		{
			if(cnt >= (int)browserList.size())
				AddEntry();
			
			if(!MiiTools::GetNandInfos(pos, miidata, browserList[cnt]))
				RemoveEntry(cnt);
			else
				cnt++;
		}
	}
	
	//! Free memory
	if (miidata)
		free(miidata);
	
	//! Sort List
	if(browserList.size() > 1)
		std::sort(browserList.begin(), browserList.end(), NameSortCallback);
}

int MiiBrowser::FilterList(std::wstring fileFilter)
{
	if(!fileFilter.empty() && (fileFilter.size() == FileFilter.size()))
		return browserList.size();
	
	if(fileFilter.size() < FileFilter.size())
		GetList();
	
	if(browserList.empty())
		return 0;
	
	if(!fileFilter.empty())
		FileFilter = fileFilter;
	else
		FileFilter.clear();

	SearchChars.clear();
	
	browserSelIndex = 0;
	
	for (u32 i = 0; i < browserList.size(); ++i)
	{
		std::wstring Filename = browserList.at(i)->name;
		if (Filename.empty())
		{
			browserList.erase(browserList.begin()+i);
			i--;
			continue;
		}
		
		if(Settings.SearchMode == SEARCH_BEGINNING)
		{
			if (FileFilter.size() > 0 && wcsncasecmp(Filename.c_str(), FileFilter.c_str(), FileFilter.size()) != 0)
			{
				browserList.erase(browserList.begin()+i);
				i--;
				continue;
			}
			
			if (Filename.size() > FileFilter.size() &&
				SearchChars.find(towupper(Filename[FileFilter.size()])) == SearchChars.end() &&
				SearchChars.find(towlower(Filename[FileFilter.size()])) == SearchChars.end())
			{
				SearchChars.insert(Filename[FileFilter.size()]);
			}
		}
		else if(Settings.SearchMode == SEARCH_CONTENT)
		{
			if(!FileFilter.empty())
			{
				if (wcscasestr(Filename.c_str(), FileFilter.c_str()) == 0)
				{
					browserList.erase(browserList.begin()+i);
					i--;
					continue;
				}
				
				const wchar_t *found = Filename.c_str();
				while((found = wcscasestr(found, FileFilter.c_str())) != 0)
				{
					found += FileFilter.size();
					wchar_t ch = towupper(*found);
					if(ch)
						SearchChars.insert(ch);
				}
			}
			else
			{
				for(const wchar_t *wPtr = Filename.c_str(); *wPtr != 0; wPtr++)
				{
					wchar_t ch = towupper(*wPtr);
					if(ch > L'@')
						SearchChars.insert(ch);
				}
			}
		}
	}

	if (browserList.size() < 2)
		SearchChars.clear();
	
	ListChanged();
	IndexChanged();
	
	return browserList.size();
}
